package ihm.panel.camera;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import ihm.applet.KrakenApplet;
import ihm.panel.PanelInterface;
import ihm.panel.TablePanel;

import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.event.TableModelEvent;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableRowSorter;

import network.KrakenClient;
import network.messages.KrakenClientMsg;
import network.messages.KrakenServerMsg;
import network.ssl.KrakenSSLClient;
import network.thread.NetworkThread;

import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;

import tools.AppletConstant;
import tools.ConfParser;
import tools.FileUtils;
import tools.StringUtils;

import bdd.sql.server.bean.Camera;
import bdd.sql.server.bean.ServerAuth;
import bdd.sql.server.bean.ServerCentral;
import bdd.sql.server.bean.ServerWeb;
import bdd.sql.server.bean.User;
import bdd.sql.server.bean.Video;
import bdd.sql.server.hibernate.HibernateUtil;

/**
 * Panneau qui affiche les vidéos liées à une caméra.
 * @author Guillaume Pocas & Jean-Fraçois Augé
 */
public class VideoPanel extends TablePanel implements ActionListener, PanelInterface {

	// generic
	private static final long serialVersionUID = 1L;
	private KrakenApplet applet;
	private Camera camera;
	
	// table
	private DefaultTableModel video_atm;
	private JTable video_jt;
	private TableRowSorter<DefaultTableModel> sorter;
	private boolean filtering = false;
	private static final int MAX_RESULT = 1000;

	private static String[] COLUMN_NAMES = {"ID", "Camera", "Nom", "Heure", "Jour", "Mois", "Année", "Poids"};
	private Object[][] column_content;

	// ihm
	private CameraPanel camera_jp;

	private JPanel bottom_jp;
	private JButton read_jb;
	private JButton filter_jb;

	private JTextField hour_filter;
	private JTextField hour_end_filter;
	private JTextField day_filter;
	private JTextField month_filter;
	private JTextField year_filter;

	// network
	private String ip_central = "";
	private String ip_auth = "";
	private String ip_storage = "";
	private String ip_web = "";
	private String ip_cam = "";
	private String user_name = "";

	private int REQUEST_TYPE_VIDEO = 1;
	private int REQUEST_TYPE_KEY = 2;

	private KrakenSSLClient cmd_client;

	private Thread cmd_thread;

	/**
	 * Constructeur.
	 * @param app
	 * @param cam_jp
	 */
	public VideoPanel(KrakenApplet app, CameraPanel cam_jp) {
		this.applet = app;
		this.camera_jp = cam_jp;
		this.initPanel();
	}

	@Override
	public void initPanel() {
		/*
		 * Table part!
		 */
		setLayout(new BorderLayout());
		video_atm = new DefaultTableModel(populateModel(), COLUMN_NAMES);

		sorter = new TableRowSorter<DefaultTableModel>(video_atm);
		
		video_jt = new JTable(video_atm) {
			private static final long serialVersionUID = 1L;

			//  Returning the Class of each column will allow different
			//  renderers to be used based on Class
			@SuppressWarnings({ "unchecked", "rawtypes" })
			public Class getColumnClass(int column) {
				return getValueAt(0, column).getClass();
			}

			//  Les quatre premières colonnes ne sont pas modifiables
			public boolean isCellEditable(int row, int column) {
				int modelColumn = convertColumnIndexToModel(column);
				return (modelColumn == 0 || modelColumn == 1
						|| modelColumn == 2 || modelColumn == 3
						|| modelColumn == 4) ? false : true;
			}
		};
		video_jt.setPreferredScrollableViewportSize(video_jt.getPreferredSize());
		video_jt.setFillsViewportHeight(true);
		JScrollPane scrollPane = new JScrollPane(video_jt);
		add(scrollPane, BorderLayout.CENTER);
		
		video_jt.setRowSorter(sorter);

		/*
		 * Buttons part!
		 */
		bottom_jp = new JPanel();

		hour_filter = new JTextField("00:00", 5);
		bottom_jp.add(hour_filter);
		
		hour_end_filter = new JTextField("23:59", 5);
		bottom_jp.add(hour_end_filter);

		day_filter = new JTextField("", 2);
		bottom_jp.add(day_filter);

		month_filter = new JTextField("", 2);
		bottom_jp.add(month_filter);

		year_filter = new JTextField("", 4);
		bottom_jp.add(year_filter);
		
		Date today = new Date();
		SimpleDateFormat day = new SimpleDateFormat("dd");
		SimpleDateFormat month = new SimpleDateFormat("MM");
		SimpleDateFormat year = new SimpleDateFormat("yyyy");
		
		day_filter.setText(day.format(today));
		month_filter.setText(month.format(today));
		year_filter.setText(year.format(today));

		filter_jb = new JButton("Rechercher");
		filter_jb.addActionListener(this);
		bottom_jp.add(filter_jb);

		read_jb = new JButton("Lire la vidéo");
		read_jb.addActionListener(this);
		bottom_jp.add(read_jb);

		add(bottom_jp, BorderLayout.SOUTH);
	}

	@Override
	public void updateTableInfo() {
		setLocked(true);
		video_atm.setDataVector(populateModel(), COLUMN_NAMES);
		setLocked(false);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public Object[][] populateModel() {
		if(applet.isUserLogged()) {
			Session session = applet.getSession();
			
			camera = this.camera_jp.getNodePanel().getCurrentCamera();

			List<Video> resultats = null;
			if(filtering)
				resultats = session.createCriteria(Video.class)
                .add(Restrictions.eq("camera", this.camera))
                .add(Restrictions.like("video_year", year_filter.getText()))
                .add(Restrictions.like("video_month", month_filter.getText()))
                .add(Restrictions.like("video_day", day_filter.getText()))
                .add(Restrictions.between("video_timeBegin", hour_filter.getText(), hour_end_filter.getText()))
                .setMaxResults(MAX_RESULT)
                .list();
			else
				resultats = session.createCriteria(Video.class)
				.add(Restrictions.eq("camera", this.camera))
				.setMaxResults(MAX_RESULT)
				.list();
			
			column_content = new Object[resultats.size()][COLUMN_NAMES.length];
			
			for(int i = 0; i < resultats.size(); i++) {
				column_content[i][0] = resultats.get(i);
				column_content[i][1] = resultats.get(i).getCamera();
				column_content[i][2] = resultats.get(i).getVideo_name();
				column_content[i][3] = resultats.get(i).getVideo_timeBegin();
				column_content[i][4] = resultats.get(i).getVideo_day();
				column_content[i][5] = resultats.get(i).getVideo_month();
				column_content[i][6] = resultats.get(i).getVideo_year();
				column_content[i][7] = FileUtils.readableFileSize(resultats.get(i).getVideo_weight());
			}
			
			session.close();
			return column_content;
		}
		else
			return null;
	}

	public Camera getCamera() { return this.camera; }
	
	public Object[][] getColumnContent() { return this.column_content; }

	@Override
	public void actionPerformed(ActionEvent e) {
		if(e.getSource().equals(filter_jb)) {
			filtering = true;
			updateTableInfo();
			filtering = false;
		}
		if(e.getSource().equals(read_jb)) {
			if(video_jt.getSelectedRows().length > 0) {
				ConfParser parseHist = new ConfParser();
				try {
					parseHist.parse(new File(AppletConstant.HIST_CONF_FILE));
				} catch (IOException e2) {
					e2.printStackTrace();
				}

				ConfParser parser = new ConfParser();
				try {
					parser.parse(new File(AppletConstant.CLIENT_CONF_FILE));
				} catch (IOException e1) {
					e1.printStackTrace();
				}

				String path = parser.getValue("DOWNLOADED_VIDEO_PATH");
				
				// liste des ips
				Session session = HibernateUtil.getSession();

				List<?> list = session.createCriteria(ServerCentral.class).list();
				ip_central = ((ServerCentral) list.get(0)).getServCentr_ip();

				list = session.createCriteria(ServerAuth.class).list();
				ip_auth = ((ServerAuth) list.get(0)).getAuth_ip_adress();

				list = session.createCriteria(ServerWeb.class).list();
				ip_web = ((ServerWeb) list.get(0)).getWebserv_ip();

				user_name = (((User) session.createCriteria(User.class).
						add(Restrictions.like("user_id", this.applet.getUser_ID())).list().get(0))).getUser_name();
				
				ip_storage = ((Video) video_jt.getValueAt(video_jt.getSelectedRow(), 0)).getStorage().getStorserv_ip();

				// liste des vidéos selectionnées
				String requested_videos = "";
				String requested_keys = "";
				boolean video = false, key = false;
				for(int i : video_jt.getSelectedRows()) {
					String videoName = ((String) video_jt.getValueAt(i, 2)).replaceAll(".mp4", "_"+user_name+".mp4");
					if(!parseHist.getChamps().containsKey(videoName)){
						requested_videos += String.valueOf(video_jt.getValueAt(i, 0))+":";
						video = true;
					}
					else{
						requested_keys += String.valueOf(video_jt.getValueAt(i, 0))+":";
						key = true;
						//camera_jp.getVlc_jp().addVideo(path+video_jt.getValueAt(i, 2).toString().replace(".encrypt", ""));
					}
				}
				
				if(video)
					requested_videos = requested_videos.substring(0, requested_videos.length()-1);
				if(key)
					requested_keys = requested_keys.substring(0, requested_keys.length()-1);

				//video
				if(video){
					System.out.println("Demande Vidéo+Clé");
					ArrayList<String> msg_list = new ArrayList<String>();
					msg_list.add(KrakenClientMsg.KRAKEN_CLIENT.makeCommand());
					msg_list.add(KrakenClientMsg.ASK_FOR_TOKEN.makeCommand(
							" "+ip_central
							+ "  "+ip_auth
							+ "  "+REQUEST_TYPE_VIDEO
							+ "  "+requested_videos
							+ "  "+ip_storage
							+ "  "+ip_cam));
					msg_list.add(KrakenClientMsg.END_CLIENT.makeCommand());
	
					KrakenClient auth_client = new KrakenClient(msg_list, ip_web);
					auth_client.connect();
					auth_client.communicate();
	
					msg_list = new ArrayList<String>();
					msg_list.add(KrakenClientMsg.KRAKEN_CLIENT.makeCommand());
					msg_list.add(KrakenClientMsg.ASK_FOR_TOKEN.makeCommand(
							" "+ip_central
							+ "  "+ip_auth
							+ "  "+REQUEST_TYPE_KEY
							+ "  "+user_name+":"+requested_videos
							+ "  "+ip_storage
							+ "  "+ip_cam));
					msg_list.add(KrakenClientMsg.END_CLIENT.makeCommand());
	
					KrakenClient key_client = new KrakenClient(msg_list, ip_web);
					key_client.connect();
					key_client.communicate();
	
					String answer_auth = auth_client.getFinalAnswer();
					String answer_key = key_client.getFinalAnswer();
	
					if(answer_auth.equalsIgnoreCase(KrakenServerMsg.END_SERVER.toString())
							&& answer_key.equalsIgnoreCase(KrakenServerMsg.END_SERVER.toString())) {
						System.out.println("\nGénération de jetons réussie\nOn se connecte au serveur en SSL !");
						// test authentification auprès du serveur site via le jeton
						String jeton_video = StringUtils.bytesToString(auth_client.getSaved_data());
						String jeton_key = StringUtils.bytesToString(key_client.getSaved_data());
	
						ArrayList<String> msg_list_cmd = new ArrayList<>();
						msg_list_cmd.add(KrakenClientMsg.KRAKEN_SSL_CLIENT.makeCommand());
						msg_list_cmd.add(KrakenClientMsg.SEND_TOKEN_FOR_DOWNLOAD.makeCommand(" "+jeton_video));
						msg_list_cmd.add(KrakenClientMsg.READY_FOR_DOWNLOAD.makeCommand(" "+path, " "+user_name));
						msg_list_cmd.add(KrakenClientMsg.SEND_TOKEN_FOR_DOWNLOAD.makeCommand(" "+jeton_key));
						msg_list_cmd.add(KrakenClientMsg.READY_FOR_DOWNLOAD.makeCommand(" "+path));
						msg_list_cmd.add(KrakenClientMsg.END_SSL_CLIENT.makeCommand());
	
						cmd_client = new KrakenSSLClient(msg_list_cmd, ip_storage, 0);
						cmd_client.setVCL_jp(camera_jp.getVlc_jp());
	
						NetworkThread cmd_network_thead = new NetworkThread(cmd_client);
						cmd_thread = new Thread(cmd_network_thead);
						cmd_thread.start();
	
						System.out.println("\nAuthentification réussie\n"+
								"Téléchargement des vidéos!");
	
						camera_jp.setPanel("Lecteur");
						camera_jp.getNodePanel().getTree().setSelectionRow(camera_jp.getNodePanel().getTree().getSelectionRows()[0]+2);
						//camera_jp.getVlc_jp().playFirst();
					}
					else
						// la génération du jeton a échouée
						JOptionPane.showMessageDialog(this,
								"L'authentification avec le serveur distant à échouée.",
								"Erreur d'authentification",
								JOptionPane.ERROR_MESSAGE);
				}
				
				//key
				if(key){
					System.out.println("Demande Clé");
					ArrayList<String> msg_list = new ArrayList<String>();
					msg_list.add(KrakenClientMsg.KRAKEN_CLIENT.makeCommand());
					msg_list.add(KrakenClientMsg.ASK_FOR_TOKEN.makeCommand(
							" "+ip_central
							+ "  "+ip_auth
							+ "  "+REQUEST_TYPE_KEY
							+ "  "+user_name+":"+requested_keys
							+ "  "+ip_storage
							+ "  "+ip_cam));
					msg_list.add(KrakenClientMsg.END_CLIENT.makeCommand());
	
					KrakenClient key_client = new KrakenClient(msg_list, ip_web);
					key_client.connect();
					key_client.communicate();
	
					String answer_key = key_client.getFinalAnswer();
	
					if(answer_key.equalsIgnoreCase(KrakenServerMsg.END_SERVER.toString())) {
						System.out.println("\nGénération de jetons réussie\nOn se connecte au serveur en SSL !");
						// test authentification auprès du serveur site via le jeton
						String jeton_key = StringUtils.bytesToString(key_client.getSaved_data());
	
						ArrayList<String> msg_list_cmd = new ArrayList<>();
						msg_list_cmd.add(KrakenClientMsg.KRAKEN_SSL_CLIENT.makeCommand());
						msg_list_cmd.add(KrakenClientMsg.SEND_TOKEN_FOR_DOWNLOAD.makeCommand(" "+jeton_key));
						msg_list_cmd.add(KrakenClientMsg.READY_FOR_DOWNLOAD.makeCommand(" "+path));
						msg_list_cmd.add(KrakenClientMsg.END_SSL_CLIENT.makeCommand());
	
						cmd_client = new KrakenSSLClient(msg_list_cmd, ip_storage, 0);
						cmd_client.setVCL_jp(camera_jp.getVlc_jp());
	
						NetworkThread cmd_network_thead = new NetworkThread(cmd_client);
						cmd_thread = new Thread(cmd_network_thead);
						cmd_thread.start();
	
						System.out.println("\nAuthentification réussie\n"+
								"Téléchargement des vidéos!");
	
						camera_jp.setPanel("Lecteur");
						camera_jp.getNodePanel().getTree().setSelectionRow(camera_jp.getNodePanel().getTree().getSelectionRows()[0]+2);
						//camera_jp.getVlc_jp().playFirst();
					}
					else
						// la génération du jeton a échouée
						JOptionPane.showMessageDialog(this,
								"L'authentification avec le serveur distant à échouée.",
								"Erreur d'authentification",
								JOptionPane.ERROR_MESSAGE);
				}
				
			}
		}
	}
	
	@Deprecated
	public void tableChanged(TableModelEvent e) {		
	}

	// setters

	public void setIp_central(String ip_central) { this.ip_central = ip_central; }
	public void setIp_auth(String ip_auth) { this.ip_auth = ip_auth; }
	public void setIp_cam(String ip_cam) { this.ip_cam = ip_cam; }

}
